package arithmetic;

import java.time.LocalDateTime;
import java.util.Properties;
import java.util.logging.Logger;

import javax.mail.Address;
import javax.mail.Folder;
import javax.mail.FolderClosedException;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.event.MessageCountAdapter;
import javax.mail.event.MessageCountEvent;

import com.sun.mail.imap.IMAPFolder;

import lombok.extern.slf4j.Slf4j;


/**
 * @author jiangfeng on 2021/10/22
 * This program demonstrates how to get e-mail messages from a POP3/IMAP server
 */

//@Slf4j
public class MailFunctionTest {
    private static final Logger log = Logger.getLogger(MailFunctionTest.class.getName());

    /**
     * Test downloading e-mail messages
     */
    public static void main(String[] args) throws NoSuchProviderException {
        // for POP3
        //String protocol = "pop3";
        //String host = "pop.gmail.com";
        //String port = "995";

        // for IMAP
        String protocol = "imap";
               String host = "imap.gmail.com";
        String port = "993";


        // 收件箱
        String mbox = "INBOX";
        String freqs = "5000";

        String userName = "Workdaytesting";
        String password = "P@ss-4GRYYy11";

        MailFunctionTest receiver = new MailFunctionTest();
        receiver.downloadEmails(protocol, host, port, userName, password);
    }


    /**
     * Returns a Properties object which is configured for a POP3/IMAP server
     *
     * @param protocol either "imap" or "pop3"
     * @return a Properties object
     */
    private Properties getServerProperties(String protocol, String host,
            String port) {
        Properties properties = new Properties();

        // server setting
        properties.put(String.format("mail.%s.host", protocol), host);
        properties.put(String.format("mail.%s.port", protocol), port);

        // SSL setting
        properties.setProperty(
                String.format("mail.%s.socketFactory.class", protocol),
                "javax.net.ssl.SSLSocketFactory");
        properties.setProperty(
                String.format("mail.%s.socketFactory.fallback", protocol),
                "false");
        properties.setProperty(
                String.format("mail.%s.socketFactory.port", protocol),
                String.valueOf(port));

        return properties;
    }

    /**
     * Downloads new messages and fetches details for each message.
     */
    public void downloadEmails(String protocol, String host, String port,
            String userName, String password) throws javax.mail.NoSuchProviderException {
        Properties properties = getServerProperties(protocol, host, port);
        Session session = Session.getDefaultInstance(properties);

        try {
            // connects to the message store
            Store store = session.getStore(protocol);
            store.connect(userName, password);

            // opens the inbox folder
            Folder folderInbox = store.getFolder("INBOX");
            folderInbox.open(Folder.READ_ONLY);

            folderInbox.addMessageCountListener(new MessageCountAdapter() {
                @Override
                public void messagesAdded(MessageCountEvent ev) {
                    Message[] msgs = ev.getMessages();
                    log.info("Got " + msgs.length + " new messages");

                    // Just dump out the new messages
                    for (int i = 0; i < msgs.length; i++) {
                        try {
                            log.info("-----"+ LocalDateTime.now()+"-------");
                            log.info("邮件id: " +
                                    msgs[i].getMessageNumber() + ":");
                            log.info("标题:"+msgs[i].getSubject());
                            log.info("内容:"+msgs[i].getContent());
                            log.info("----------------------");
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            });

            log.info("---启动成功开始监听邮件---");
            // 检查是否支持imap idle,尝试使用idle
            int freq = 500;
            boolean supportsIdle = false;
            boolean isOpenidle = true;
            try {
                if (isOpenidle && folderInbox instanceof IMAPFolder) {
                    IMAPFolder f = (IMAPFolder) folderInbox;
                    f.idle();
                    supportsIdle = true;
                }
            } catch (FolderClosedException fex) {
                throw fex;
            }
            while (true) {
                if (supportsIdle && folderInbox instanceof IMAPFolder) {
                    IMAPFolder f = (IMAPFolder) folderInbox;
                    //                    f.idle();
                    startListening(f);
                } else {
                    log.info("idle不支持进入轮询");
                    //Thread.sleep(freq); // sleep for freq milliseconds

                    // 注意。getMessageCount时会触发监听器
                    folderInbox.getMessageCount();
                }
            }
            //getAndPrintMail(folderInbox);

            // disconnect
            //            folderInbox.close(false);
            //            store.close();
        } catch (MessagingException ex) {
            log.info("Could not connect to the message store");
            //ex.printStackTrace();
        } catch (Exception e) {
            //log.error("Exception", e);
        }
    }

    public void startListening(IMAPFolder imapFolder) {
        // We need to create a new thread to keep alive the connection
       /* Thread t = new Thread(
                new KeepAliveRunnable(imapFolder), "IdleConnectionKeepAlive"
        );

        t.start();*/

        while (!Thread.interrupted()) {
            //log.debug("Starting IDLE");
            try {
                imapFolder.idle();
            } catch (MessagingException e) {
               // log.warn("Messaging exception during IDLE", e);
                throw new RuntimeException(e);
            }
        }

        // Shutdown keep alive thread
        /*if (t.isAlive()) {
            t.interrupt();
        }*/
    }

    private void getAndPrintMail(Folder folderInbox) throws MessagingException {
        // fetches new messages from server
        Message[] messages = folderInbox.getMessages();

        for (int i = 0; i < messages.length; i++) {
            printMsg(messages[i]);
        }
    }

    private void printMsg(Message msg) throws MessagingException {
        Address[] fromAddress = msg.getFrom();
        String from = fromAddress[0].toString();
        String subject = msg.getSubject();
        String toList = parseAddresses(msg
                .getRecipients(RecipientType.TO));
        String ccList = parseAddresses(msg
                .getRecipients(RecipientType.CC));
        String sentDate = msg.getSentDate().toString();

        String contentType = msg.getContentType();
        String messageContent = "";

        if (contentType.contains("text/plain")
                || contentType.contains("text/html")) {
            try {
                Object content = msg.getContent();
                if (content != null) {
                    messageContent = content.toString();
                }
            } catch (Exception ex) {
                messageContent = "[Error downloading content]";
                ex.printStackTrace();
            }
        }

        // print out details of each message
        log.info("new Message #" +   ":");
        log.info("\t From: " + from);
        log.info("\t To: " + toList);
        log.info("\t CC: " + ccList);
        log.info("\t Subject: " + subject);
        log.info("\t Sent Date: " + sentDate);
        log.info("\t Message: " + messageContent);
    }

    /**
     * Returns a list of addresses in String format separated by comma
     *
     * @param address an array of Address objects
     * @return a string represents a list of addresses
     */
    private String parseAddresses(Address[] address) {
        String listAddress = "";

        if (address != null) {
            for (int i = 0; i < address.length; i++) {
                listAddress += address[i].toString() + ", ";
            }
        }
        if (listAddress.length() > 1) {
            listAddress = listAddress.substring(0, listAddress.length() - 2);
        }

        return listAddress;
    }


}